home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / multipad.zip / MULTIPAD.C < prev    next >
Text File  |  1992-07-17  |  27KB  |  924 lines

  1. /***************************************************************************
  2.  *                                       *
  3.  *  PROGRAM    : MultiPad.c                           *
  4.  *                                       *
  5.  *  PURPOSE    : To give a multi-Notepad demonstration of the new MDI       *
  6.  *          API in Windows 3.0                       *
  7.  *                                       *
  8.  *  FUNCTIONS    : WinMain()          - Calls the initialization function  *
  9.  *                    and processes message loop       *
  10.  *                                       *
  11.  *          MPFrameWndProc()    - Window function for the "frame"    *
  12.  *                    window, which controls the menu    *
  13.  *                    and contains the MDI document       *
  14.  *                    windows as child windows.       *
  15.  *                                       *
  16.  *          MPMDIChildWndProc() - Window function for the individual *
  17.  *                    document windows           *
  18.  *                                       *
  19.  *          InitializeMenu()    - Handles enabling/greying of menu   *
  20.  *                    items according to the app's state.*
  21.  *                                       *
  22.  *          CloseAllChildren    - Destroys all MDI child windows.    *
  23.  *                                       *
  24.  *          CommandHandler()    - Processes the "frame" window's     *
  25.  *                    WM_COMMAND messages.           *
  26.  *                                       *
  27.  *          AboutDlgProc()      - Dialog function for the ubiquitous *
  28.  *                    About.. dialog.            *
  29.  *                                       *
  30.  *          SetWrap()          - Alters word wrapping in the edit   *
  31.  *                    control.               *
  32.  *                                       *
  33.  *          MPError()          - Flashes an error messagebox.       *
  34.  *                                       *
  35.  *          QueryCloseChild     - Prompts for saving current MDI       *
  36.  *                    child window.               *
  37.  *                                       *
  38.  *          QueryCloseAllChildren() - Asks whether it is OK to close *
  39.  *                        down app.               *
  40.  *                                       *
  41.  ***************************************************************************/
  42. // COPYRIGHT:
  43. //
  44. //   (C) Copyright Microsoft Corp. 1992.  All rights reserved.
  45. //
  46. //   You have a royalty-free right to use, modify, reproduce and
  47. //   distribute the Sample Files (and/or any modified version) in
  48. //   any way you find useful, provided that you agree that
  49. //   Microsoft has no warranty obligations or liability for any
  50. //   Sample Application Files which are modified.
  51.  
  52.  
  53. #include "multipad.h"
  54. #include "commdlg.h"
  55.  
  56. /* global variables used in this module or among more than one module */
  57. PRINTDLG pd;      /* Common print dialog structure */
  58. HANDLE hInst;                /* Program instance handle             */
  59. HANDLE hAccel;                /* Main accelerator resource         */
  60. HWND hwndFrame         = NULL;    /* Handle to main window             */
  61. HWND hwndMDIClient     = NULL;    /* Handle to MDI client             */
  62. HWND hwndActive      = NULL;    /* Handle to currently activated child   */
  63. HWND hwndActiveEdit     = NULL;    /* Handle to edit control             */
  64. LONG styleDefault    = WS_MAXIMIZE; /* Default style bits for child windows  */
  65.                     /* The first window is created maximized */
  66.                     /* to resemble Notepad.  Later children  */
  67.                     /* are normal windows.             */
  68. LPSTR lpMenu         = (LPSTR)IDMULTIPAD;  /* Contains the resource id of the        */
  69.                     /* current frame menu             */
  70.  
  71.  
  72. /* Forward declarations of helper functions in this module */
  73. VOID NEAR PASCAL InitializeMenu (HANDLE);
  74. VOID NEAR PASCAL CommandHandler (HWND,WORD);
  75. VOID NEAR PASCAL SetWrap (HWND,BOOL);
  76. BOOL NEAR PASCAL QueryCloseAllChildren ( VOID );
  77. int  NEAR PASCAL QueryCloseChild (HWND);
  78.  
  79. /****************************************************************************
  80.  *                                        *
  81.  *  FUNCTION   : WinMain(HANDLE, HANDLE, LPSTR, int)                *
  82.  *                                        *
  83.  *  PURPOSE    : Creates the "frame" window, does some initialization and   *
  84.  *         enters the message loop.                    *
  85.  *                                        *
  86.  ****************************************************************************/
  87. int NEAR PASCAL WinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow)
  88.  
  89. HANDLE hInstance;
  90. HANDLE hPrevInstance;
  91. LPSTR  lpszCmdLine;
  92. int    nCmdShow;
  93. {
  94.     MSG msg;
  95.  
  96.     hInst = hInstance;
  97.  
  98.     /* If this is the first instance of the app. register window classes */
  99.     if (!hPrevInstance){
  100.     if (!InitializeApplication ())
  101.         return 0;
  102.     }
  103.  
  104.     /* Create the frame and do other initialization */
  105.     if (!InitializeInstance (lpszCmdLine, nCmdShow))
  106.     return 0;
  107.  
  108.     /* Enter main message loop */
  109.     while (GetMessage (&msg, NULL, 0, 0)){
  110.     /* If a keyboard message is for the MDI , let the MDI client
  111.      * take care of it.  Otherwise, check to see if it's a normal
  112.      * accelerator key (like F3 = find next).  Otherwise, just handle
  113.      * the message as usual.
  114.      */
  115.     if ( !TranslateMDISysAccel (hwndMDIClient, &msg) &&
  116.          !TranslateAccelerator (hwndFrame, hAccel, &msg)){
  117.         TranslateMessage (&msg);
  118.         DispatchMessage (&msg);
  119.     }
  120.     }
  121.     return 0;
  122. }
  123.  
  124. /****************************************************************************
  125.  *                                        *
  126.  *  FUNCTION   : MPFrameWndProc (hwnd, msg, wParam, lParam )            *
  127.  *                                        *
  128.  *  PURPOSE    : The window function for the "frame" window, which controls *
  129.  *         the menu and encompasses all the MDI child windows. Does   *
  130.  *         the major part of the message processing. Specifically, in *
  131.  *         response to:                            *
  132.  *                                        *
  133.  *             WM_CREATE        : Creates and displays the "frame". *
  134.  *                                        *
  135.  *             WM_INITMENU    : Sets up the state of the menu.    *
  136.  *                                        *
  137.  *             WM_WININICHANGE &  : If default printer characteristics*
  138.  *             WM_DEVMODECHANGE      have been changed, reinitialises  *
  139.  *                      printer DC.                *
  140.  *                                        *
  141.  *             WM_COMMAND     : Passes control to a command-        *
  142.  *                      handling function.            *
  143.  *                                        *
  144.  *             WM_CLOSE        : Quits the app. if all the child   *
  145.  *                      windows agree.            *
  146.  *                                        *
  147.  *             WM_QUERYENDSESSION : Checks that all child windows     *
  148.  *                      agree to quit.            *
  149.  *                                        *
  150.  *             WM_DESTROY     : Destroys frame window and quits   *
  151.  *                      app.                    *
  152.  *                                        *
  153.  ****************************************************************************/
  154. LONG FAR PASCAL MPFrameWndProc ( hwnd, msg, wParam, lParam )
  155.  
  156. register HWND     hwnd;
  157. UINT         msg;
  158. register WPARAM    wParam;
  159. LPARAM           lParam;
  160.  
  161. {
  162.     switch (msg){
  163.       case WM_CREATE:{
  164.  
  165.         CLIENTCREATESTRUCT ccs;
  166.  
  167.         /* Find window menu where children will be listed */
  168.         ccs.hWindowMenu = GetSubMenu (GetMenu(hwnd),WINDOWMENU);
  169.         ccs.idFirstChild = IDM_WINDOWCHILD;
  170.  
  171.         /* Create the MDI client filling the client area */
  172.         hwndMDIClient = CreateWindow ("mdiclient",
  173.                       NULL,
  174.                       WS_CHILD | WS_CLIPCHILDREN |
  175.                       WS_VSCROLL | WS_HSCROLL,
  176.                       0,
  177.                       0,
  178.                       0,
  179.                       0,
  180.                       hwnd,
  181.                       0xCAC,
  182.                       hInst,
  183.                       (LPSTR)&ccs);
  184.  
  185.  
  186.         ShowWindow (hwndMDIClient,SW_SHOW);
  187.         break;
  188.     }
  189.  
  190.     case WM_INITMENU:
  191.         /* Set up the menu state */
  192.         InitializeMenu ((HMENU)wParam);
  193.         break;
  194.  
  195.     case WM_COMMAND:
  196.         /* Direct all menu selection or accelerator commands to another
  197.          * function
  198.          */
  199.         CommandHandler (hwnd,wParam);
  200.         break;
  201.  
  202.     case WM_CLOSE:
  203.         /* don't close if any children cancel the operation */
  204.         if (!QueryCloseAllChildren ())
  205.         break;
  206.         DestroyWindow (hwnd);
  207.         break;
  208.  
  209.     case WM_QUERYENDSESSION:
  210.         /*    Before session ends, check that all files are saved */
  211.         return QueryCloseAllChildren ();
  212.  
  213.     case WM_DESTROY:
  214.         PostQuitMessage (0);
  215.         break;
  216.  
  217.     default:
  218.         /*    use DefFrameProc() instead of DefWindowProc() since there
  219.          *    are things that have to be handled differently because of MDI
  220.          */
  221.         return DefFrameProc (hwnd,hwndMDIClient,msg,wParam,lParam);
  222.     }
  223.     return 0;
  224. }
  225.  
  226. /****************************************************************************
  227.  *                                        *
  228.  *  FUNCTION   : MPMDIWndProc ( hwnd, msg, wParam, lParam )            *
  229.  *                                        *
  230.  *  PURPOSE    : The window function for the individual document windows,   *
  231.  *         each of which has a "note". Each of these windows contain  *
  232.  *         one multi-line edit control filling their client area.     *
  233.  *         In response to the following:                    *
  234.  *                                        *
  235.  *             WM_CREATE        : Creates & diplays an edit control *
  236.  *                      and does some initialization.     *
  237.  *                                        *
  238.  *             WM_MDIACTIVATE    : Activates/deactivates the child.  *
  239.  *                                        *
  240.  *             WM_SETFOCUS    : Sets focus on the edit control.   *
  241.  *                                        *
  242.  *             WM_SIZE        : Resizes the edit control.        *
  243.  *                                        *
  244.  *             WM_COMMAND     : Processes some of the edit        *
  245.  *                      commands, saves files and alters  *
  246.  *                      the edit wrap state.            *
  247.  *                                        *
  248.  *             WM_CLOSE        : Closes child if it is ok to do so.*
  249.  *                                        *
  250.  *             WM_QUERYENDSESSION : Same as above.            *
  251.  *                                        *
  252.  ****************************************************************************/
  253.  
  254. LONG FAR PASCAL MPMDIChildWndProc ( hwnd, msg, wParam, lParam )
  255.  
  256. register HWND    hwnd;
  257. UINT        msg;
  258. register WPARAM   wParam;
  259. LPARAM          lParam;
  260.  
  261. {
  262.     HWND hwndEdit;
  263.  
  264.     switch (msg){
  265.     case WM_CREATE:
  266.         /* Create an edit control */
  267.         hwndEdit = CreateWindow ("edit",
  268.                      NULL,
  269.                      WS_CHILD|WS_HSCROLL|WS_MAXIMIZE|WS_VISIBLE|WS_VSCROLL|ES_AUTOHSCROLL|ES_AUTOVSCROLL|ES_MULTILINE,
  270.                      0,
  271.                      0,
  272.                      0,
  273.                      0,
  274.                      hwnd,
  275.                      ID_EDIT,
  276.                      hInst,
  277.                      NULL);
  278.  
  279.         /* Remember the window handle and initialize some window attributes */
  280.         SetWindowWord (hwnd, GWW_HWNDEDIT, (WORD)hwndEdit);
  281.         SetWindowWord (hwnd, GWW_CHANGED, FALSE);
  282.         SetWindowWord (hwnd, GWW_WORDWRAP, FALSE);
  283.         SetWindowWord (hwnd, GWW_UNTITLED, TRUE);
  284.         SetFocus (hwndEdit);
  285.         break;
  286.  
  287.     case WM_MDIACTIVATE:
  288.         /* If we're activating this child, remember it */
  289.         if (wParam){
  290.         hwndActive     = hwnd;
  291.         hwndActiveEdit = (HWND)GetWindowWord (hwnd, GWW_HWNDEDIT);
  292.         }
  293.         else{
  294.         hwndActive     = NULL;
  295.         hwndActiveEdit = NULL;
  296.         }
  297.         break;
  298.  
  299.     case WM_QUERYENDSESSION:
  300.         /* Prompt to save the child */
  301.         return !QueryCloseChild (hwnd);
  302.  
  303.     case WM_CLOSE:
  304.         /* If its OK to close the child, do so, else ignore */
  305.         if (QueryCloseChild (hwnd))
  306.         goto CallDCP;
  307.         else
  308.         break;
  309.  
  310.     case WM_SIZE:{
  311.         RECT rc;
  312.  
  313.         /* On creation or resize, size the edit control. */
  314.         hwndEdit = GetWindowWord (hwnd, GWW_HWNDEDIT);
  315.         GetClientRect (hwnd, &rc);
  316.         MoveWindow (hwndEdit,
  317.             rc.left,
  318.             rc.top,
  319.             rc.right-rc.left,
  320.             rc.bottom-rc.top,
  321.             TRUE);
  322.         goto CallDCP;
  323.     }
  324.  
  325.     case WM_SETFOCUS:
  326.         SetFocus (GetWindowWord (hwnd, GWW_HWNDEDIT));
  327.         break;
  328.  
  329.     case WM_COMMAND:
  330.         switch (wParam){
  331.         case ID_EDIT:
  332.             switch (HIWORD(lParam)){
  333.             case EN_CHANGE:
  334.  
  335.                 /* If the contents of the edit control have changed,
  336.                    set the changed flag
  337.                  */
  338.                 SetWindowWord (hwnd, GWW_CHANGED, TRUE);
  339.                 break;
  340.  
  341.             case EN_ERRSPACE:
  342.                 /* If the control is out of space, honk */
  343.                 MessageBeep (0);
  344.                 break;
  345.  
  346.             default:
  347.                 goto CallDCP;
  348.             }
  349.             break;
  350.  
  351.         case IDM_FILESAVE:
  352.             /* If empty file, ignore save */
  353.             if ((GetWindowWord(hwnd, GWW_UNTITLED)) && (!ChangeFile(hwnd)))
  354.             break;
  355.  
  356.             /* Save the contents of the edit control and reset the
  357.              * changed flag
  358.              */
  359.             SaveFile (hwnd);
  360.             SetWindowWord (hwnd, GWW_CHANGED, FALSE);
  361.             break;
  362.  
  363.         case IDM_EDITWRAP: {
  364.             int fWrap = GetWindowWord (hwnd, GWW_WORDWRAP);
  365.  
  366.             /* Set the wrap state, or report it */
  367.             if (LOWORD (lParam)){
  368.             fWrap = !fWrap;
  369.             SetWrap (hwnd, fWrap);
  370.             }
  371.  
  372.             /* return wrap state */
  373.             return fWrap;
  374.         }
  375.  
  376.         default:
  377.             goto CallDCP;
  378.         }
  379.         break;
  380.  
  381.     default:
  382. CallDCP:
  383.         /* Again, since the MDI default behaviour is a little different,
  384.          * call DefMDIChildProc instead of DefWindowProc()
  385.          */
  386.         return DefMDIChildProc (hwnd, msg, wParam, lParam);
  387.     }
  388.     return FALSE;
  389. }
  390.  
  391.  
  392. /****************************************************************************
  393.  *                                        *
  394.  *  FUNCTION   : AboutDlgProc ( hwnd, msg, wParam, lParam )            *
  395.  *                                        *
  396.  *  PURPOSE    : Dialog function for the About MultiPad... dialog.        *
  397.  *                                        *
  398.  ****************************************************************************/
  399. BOOL FAR PASCAL AboutDlgProc ( hwnd, msg, wParam, lParam )
  400. HWND          hwnd;
  401. register WORD msg;
  402. register WORD wParam;
  403. LONG          lParam;
  404. {
  405.     switch (msg){
  406.     case WM_INITDIALOG:
  407.         /* nothing to initialize */
  408.         break;
  409.  
  410.     case WM_COMMAND:
  411.         switch (wParam){
  412.         case IDOK:
  413.         case IDCANCEL:
  414.             EndDialog(hwnd, 0);
  415.             break;
  416.  
  417.         default:
  418.             return FALSE;
  419.         }
  420.         break;
  421.  
  422.     default:
  423.         return FALSE;
  424.     }
  425.  
  426.     return TRUE;
  427. }
  428.  
  429. /****************************************************************************
  430.  *                                        *
  431.  *  FUNCTION   : Initializemenu ( hMenu )                    *
  432.  *                                        *
  433.  *  PURPOSE    : Sets up greying, enabling and checking of main menu items  *
  434.  *         based on the app's state.                                  *
  435.  *                                        *
  436.  ****************************************************************************/
  437. VOID NEAR PASCAL InitializeMenu ( hmenu )
  438. register HANDLE hmenu;
  439. {
  440.     register WORD status;
  441.     int       i;
  442.     long      l;
  443.  
  444.     /* Is there any active child to talk to? */
  445.     if (hwndActiveEdit){
  446.     /* If edit control can respond to an undo request, enable the
  447.      * undo selection.
  448.      */
  449.     if (SendMessage (hwndActiveEdit, EM_CANUNDO, 0, 0L))
  450.         status = MF_ENABLED;
  451.     else
  452.         status = MF_GRAYED;
  453.     EnableMenuItem (hmenu, IDM_EDITUNDO, status);
  454.  
  455.     /* If edit control is non-empty, allow cut/copy/clear */
  456.     l      = SendMessage (hwndActiveEdit, EM_GETSEL, 0, 0L);
  457.     status = (HIWORD(l) == LOWORD(l)) ? MF_GRAYED : MF_ENABLED;
  458.     EnableMenuItem (hmenu, IDM_EDITCUT, status);
  459.     EnableMenuItem (hmenu, IDM_EDITCOPY, status);
  460.     EnableMenuItem (hmenu, IDM_EDITCLEAR, status);
  461.  
  462.     status=MF_GRAYED;
  463.     /* If the clipboard contains some CF_TEXT data, allow paste */
  464.     if (OpenClipboard (hwndFrame)){
  465.         int wFmt = 0;
  466.  
  467.         while (wFmt = EnumClipboardFormats (wFmt))
  468.         if (wFmt == CF_TEXT){
  469.             status = MF_ENABLED;
  470.             break;
  471.         }
  472.  
  473.         CloseClipboard ();
  474.     }
  475.     EnableMenuItem (hmenu, IDM_EDITPASTE, status);
  476.  
  477.     /* Set the word wrap state for the window */
  478.     if ((WORD) SendMessage (hwndActive, WM_COMMAND, IDM_EDITWRAP, 0L))
  479.         status = MF_CHECKED;
  480.     else
  481.         status = MF_UNCHECKED;
  482.     CheckMenuItem (hmenu, IDM_EDITWRAP, status);
  483.  
  484.     /* Enable search menu items only if there is a search string */
  485.     if (*szSearch)
  486.         status = MF_ENABLED;
  487.     else
  488.         status = MF_GRAYED;
  489.     EnableMenuItem (hmenu, IDM_SEARCHNEXT, status);
  490.     EnableMenuItem (hmenu, IDM_SEARCHPREV, status);
  491.  
  492.     /* select all and wrap toggle always enabled */
  493.     status = MF_ENABLED;
  494.     EnableMenuItem(hmenu, IDM_EDITSELECT, status);
  495.     EnableMenuItem(hmenu, IDM_EDITWRAP, status);
  496.     EnableMenuItem(hmenu, IDM_SEARCHFIND, status);
  497.     }
  498.     else {
  499.     /* There are no active child windows */
  500.     status = MF_GRAYED;
  501.  
  502.     /* No active window, so disable everything */
  503.     for (i = IDM_EDITFIRST; i <= IDM_EDITLAST; i++)
  504.         EnableMenuItem (hmenu, i, status);
  505.  
  506.     CheckMenuItem (hmenu, IDM_EDITWRAP, MF_UNCHECKED);
  507.  
  508.     for (i = IDM_SEARCHFIRST; i <= IDM_SEARCHLAST; i++)
  509.         EnableMenuItem (hmenu, i, status);
  510.  
  511.     EnableMenuItem (hmenu, IDM_FILEPRINT, status);
  512.  
  513.     }
  514.  
  515.     /* The following menu items are enabled if there is an active window */
  516.     EnableMenuItem (hmenu, IDM_FILESAVE, status);
  517.     EnableMenuItem (hmenu, IDM_FILESAVEAS, status);
  518.     EnableMenuItem (hmenu, IDM_WINDOWTILE, status);
  519.     EnableMenuItem (hmenu, IDM_WINDOWCASCADE, status);
  520.     EnableMenuItem (hmenu, IDM_WINDOWICONS, status);
  521.     EnableMenuItem (hmenu, IDM_WINDOWCLOSEALL, status);
  522.  
  523. }
  524.  
  525. /****************************************************************************
  526.  *                                        *
  527.  *  FUNCTION   : CloseAllChildren ()                        *
  528.  *                                        *
  529.  *  PURPOSE    : Destroys all MDI child windows.                *
  530.  *                                        *
  531.  ****************************************************************************/
  532. VOID NEAR PASCAL CloseAllChildren ()
  533. {
  534.     register HWND hwndT;
  535.  
  536.     /* hide the MDI client window to avoid multiple repaints */
  537.     ShowWindow(hwndMDIClient,SW_HIDE);
  538.  
  539.     /* As long as the MDI client has a child, destroy it */
  540.     while ( hwndT = GetWindow (hwndMDIClient, GW_CHILD)){
  541.  
  542.     /* Skip the icon title windows */
  543.     while (hwndT && GetWindow (hwndT, GW_OWNER))
  544.         hwndT = GetWindow (hwndT, GW_HWNDNEXT);
  545.  
  546.     if (!hwndT)
  547.         break;
  548.  
  549.     SendMessage (hwndMDIClient, WM_MDIDESTROY, (WORD)hwndT, 0L);
  550.     }
  551. }
  552.  
  553. /****************************************************************************
  554.  *                                        *
  555.  *  FUNCTION   : CommandHandler ()                        *
  556.  *                                        *
  557.  *  PURPOSE    : Processes all "frame" WM_COMMAND messages.            *
  558.  *                                        *
  559.  ****************************************************************************/
  560. VOID NEAR PASCAL CommandHandler ( hwnd, wParam )
  561. register HWND hwnd;
  562. register WORD wParam;
  563.  
  564. {
  565.    DWORD FlagSave;
  566.    
  567.    switch (wParam){
  568.     case IDM_FILENEW:
  569.         /* Add a new, empty MDI child */
  570.         AddFile (NULL);
  571.         break;
  572.  
  573.     case IDM_FILEOPEN:
  574.         ReadFile (hwnd);
  575.         break;
  576.  
  577.     case IDM_FILESAVE:
  578.         /* Save the active child MDI */
  579.         SendMessage (hwndActive, WM_COMMAND, IDM_FILESAVE, 0L);
  580.         break;
  581.  
  582.     case IDM_FILESAVEAS:
  583.         /* Save active child MDI under another name */
  584.         if (ChangeFile (hwndActive))
  585.         SendMessage (hwndActive, WM_COMMAND, IDM_FILESAVE, 0L);
  586.         break;
  587.  
  588.     case IDM_FILEPRINT:
  589.         /* Print the active child MDI */
  590.         PrintFile (hwndActive);
  591.         break;
  592.  
  593.     case IDM_FILESETUP:
  594.        FlagSave = pd.Flags;
  595.        pd.Flags |= PD_PRINTSETUP;    /* Set option */
  596.        PrintDlg((LPPRINTDLG)&pd);
  597.        pd.Flags = FlagSave;          /* Remove option */
  598.        break;
  599.         
  600. #if 0      
  601.       /* Set up the printer environment for this app */
  602.         GetInitializationData (hwnd);
  603.         break;
  604. #endif
  605.  
  606.     case IDM_FILEMENU:{
  607.  
  608.           /* lengthen / shorten the size of the MDI menu */
  609.           HMENU hMenu;
  610.           HMENU hWindowMenu;
  611.           int i;
  612.  
  613.           if (lpMenu == (LPSTR)IDMULTIPAD){
  614.           lpMenu = (LPSTR)IDMULTIPAD2;
  615.           i     = SHORTMENU;
  616.           }
  617.           else{
  618.           lpMenu = (LPSTR)IDMULTIPAD;
  619.           i     = WINDOWMENU;
  620.           }
  621.  
  622.           hMenu = LoadMenu (hInst, lpMenu);
  623.           hWindowMenu = GetSubMenu (hMenu, i);
  624.  
  625.           /* Set the new menu */
  626.           hMenu = (HMENU)SendMessage (hwndMDIClient,
  627.                       WM_MDISETMENU,
  628.                       0,
  629.                       MAKELONG(hMenu,hWindowMenu));
  630.  
  631.           DestroyMenu (hMenu);
  632.           DrawMenuBar (hwndFrame);
  633.           break;
  634.     }
  635.  
  636.     case IDM_FILEEXIT:
  637.         /* Close Multipad */
  638.         SendMessage (hwnd, WM_CLOSE, 0, 0L);
  639.         break;
  640.  
  641.     case IDM_HELPABOUT:{
  642.         /* Bring up the ubiquitous Ego box */
  643.         FARPROC lpfn;
  644.  
  645.         lpfn = MakeProcInstance(AboutDlgProc, hInst);
  646.         DialogBox (hInst, IDD_ABOUT, hwnd, lpfn);
  647.         FreeProcInstance (lpfn);
  648.         break;
  649.     }
  650.  
  651.     /* The following are edit commands. Pass these off to the active
  652.      * child's edit control window.
  653.      */
  654.     case IDM_EDITCOPY:
  655.         SendMessage (hwndActiveEdit, WM_COPY, 0, 0L);
  656.         break;
  657.  
  658.     case IDM_EDITPASTE:
  659.         SendMessage (hwndActiveEdit, WM_PASTE, 0, 0L);
  660.         break;
  661.  
  662.     case IDM_EDITCUT:
  663.         SendMessage (hwndActiveEdit, WM_CUT, 0, 0L);
  664.         break;
  665.  
  666.     case IDM_EDITCLEAR:
  667.         SendMessage (hwndActiveEdit, EM_REPLACESEL, 0,( LONG)(LPSTR)"");
  668.         break;
  669.  
  670.     case IDM_EDITSELECT:
  671.         SendMessage (hwndActiveEdit, EM_SETSEL, 0, MAKELONG(0, 0xe000));
  672.         break;
  673.  
  674.     case IDM_EDITUNDO:
  675.         SendMessage (hwndActiveEdit, EM_UNDO, 0, 0L);
  676.         break;
  677.  
  678.     case IDM_EDITWRAP:
  679.         SendMessage (hwndActive, WM_COMMAND, IDM_EDITWRAP, 1L);
  680.         break;
  681.  
  682.     case IDM_SEARCHFIND:
  683.         /* Put up the find dialog box */
  684.         Find ();
  685.         break;
  686.  
  687.     case IDM_SEARCHNEXT:
  688.         /* Find next occurence */
  689.         FindNext ();
  690.         break;
  691.  
  692.     case IDM_SEARCHPREV:
  693.         /* Find previous occurence */
  694.         FindPrev ();
  695.         break;
  696.  
  697.     /* The following are window commands - these are handled by the
  698.      * MDI Client.
  699.      */
  700.     case IDM_WINDOWTILE:
  701.         /* Tile MDI windows */
  702.         SendMessage (hwndMDIClient, WM_MDITILE, 0, 0L);
  703.         break;
  704.  
  705.     case IDM_WINDOWCASCADE:
  706.         /* Cascade MDI windows */
  707.         SendMessage (hwndMDIClient, WM_MDICASCADE, 0, 0L);
  708.         break;
  709.  
  710.     case IDM_WINDOWICONS:
  711.         /* Auto - arrange MDI icons */
  712.         SendMessage (hwndMDIClient, WM_MDIICONARRANGE, 0, 0L);
  713.         break;
  714.  
  715.     case IDM_WINDOWCLOSEALL:
  716.         /* Abort operation if something is not saved */
  717.         if (!QueryCloseAllChildren())
  718.         break;
  719.  
  720.         CloseAllChildren();
  721.  
  722.         /* Show the window since CloseAllChilren() hides the window
  723.          * for fewer repaints.
  724.          */
  725.         ShowWindow( hwndMDIClient, SW_SHOW);
  726.  
  727.         break;
  728.  
  729.     default:
  730.        /*
  731.         * This is essential, since there are frame WM_COMMANDS generated
  732.         * by the MDI system for activating child windows via the
  733.         * window menu.
  734.         */
  735.         DefFrameProc(hwnd, hwndMDIClient, WM_COMMAND, wParam, 0L);
  736.     }
  737. }
  738. /****************************************************************************
  739.  *                                        *
  740.  *  FUNCTION   : SetWrap ()                            *
  741.  *                                        *
  742.  *  PURPOSE    : Changes the word wrapping in an edit control. Since this   *
  743.  *         cannot be done by direct means, the function creates a new *
  744.  *         edit control, moves data from the old control to the new   *
  745.  *         control and destroys the original control. Note that the   *
  746.  *         function assumes that the child being modified is currently*
  747.  *         active.                            *        *
  748.  *                                        *
  749.  ****************************************************************************/
  750.  
  751. VOID NEAR PASCAL SetWrap(hwnd, fWrap)
  752. HWND hwnd;
  753. BOOL fWrap;
  754.  
  755. {
  756.     LONG    dws;
  757.     HANDLE  hT;
  758.     HANDLE  hTT;
  759.     HWND    hwndOld;
  760.     HWND    hwndNew;
  761.  
  762.     /* Change word wrap mode */
  763.     SetWindowWord (hwnd, GWW_WORDWRAP, fWrap);
  764.  
  765.     /* Create the appropriate window style, adding a horizontal scroll
  766.      * facility if wrapping is not present.
  767.      */
  768.     dws = WS_CHILD | WS_VSCROLL | ES_AUTOVSCROLL | ES_MULTILINE;
  769.     if (!fWrap)
  770.     dws |= WS_HSCROLL | ES_AUTOHSCROLL;
  771.  
  772.     /* Create a new child window */
  773.     hwndNew = CreateWindow ( "edit",
  774.                  NULL,
  775.                  dws,
  776.                  0,
  777.                  SW_SHOW,
  778.                  0,
  779.                  0,
  780.                  hwnd,
  781.                  ID_EDIT,
  782.                  hInst,
  783.                  NULL);
  784.  
  785.     /* Get handle to current edit control */
  786.     hwndOld = GetWindowWord (hwnd, GWW_HWNDEDIT);
  787.  
  788.     /* Get the data handle of the old control */
  789.     hT = (HANDLE)SendMessage (hwndOld, EM_GETHANDLE, 0, 0L);
  790.  
  791.     /* Create a dummy data handle and make it the handle to
  792.      * the old edit control( hT still references the text of
  793.      * old control).
  794.      */
  795.     hTT = LocalAlloc (LHND, 0);
  796.     SendMessage (hwndOld, EM_SETHANDLE, hTT, 0L);
  797.  
  798.     /* Make the new window the window of interest and destroy the
  799.      * old control.
  800.      */
  801.     SetWindowWord (hwnd, GWW_HWNDEDIT, hwndNew);
  802.     hwndActiveEdit = hwndNew;
  803.     DestroyWindow (hwndOld);
  804.  
  805.     /* Cause the window to be properly sized */
  806.     SendMessage (hwnd, WM_SIZE, 0, 0L);
  807.  
  808.     /* Free the new window's old data handle and set it to
  809.      * hT (text of old edit control)
  810.      */
  811.     LocalFree ((HANDLE)SendMessage (hwndNew, EM_GETHANDLE, 0, 0L));
  812.     SendMessage (hwndNew, EM_SETHANDLE, hT, 0L);
  813.  
  814.     ShowWindow (hwndNew, SW_SHOW);
  815.  
  816.     /* Set focus to the new edit control */
  817.     SetFocus (hwndNew);
  818.  
  819. }
  820.  
  821.  
  822. /****************************************************************************
  823.  *                                        *
  824.  *  FUNCTION   : MPError ( hwnd, flags, id, ...)                *
  825.  *                                        *
  826.  *  PURPOSE    : Flashes a Message Box to the user. The format string is    *
  827.  *         taken from the STRINGTABLE.                    *
  828.  *                                        *
  829.  *  RETURNS    : Returns value returned by MessageBox() to the caller.        *
  830.  *                                        *
  831.  ****************************************************************************/
  832. short FAR CDECL MPError(hwnd, bFlags, id, ...)
  833. HWND hwnd;
  834. WORD bFlags;
  835. WORD id;
  836. {
  837.     char sz[160];
  838.     char szFmt[128];
  839.  
  840.     LoadString (hInst, id, szFmt, sizeof (szFmt));
  841.     wvsprintf (sz, szFmt, (LPSTR)(&id + 1));
  842.     LoadString (hInst, IDS_APPNAME, szFmt, sizeof (szFmt));
  843.     return MessageBox (hwndFrame, sz, szFmt, bFlags);
  844. }
  845.  
  846.  
  847. /****************************************************************************
  848.  *                                        *
  849.  *  FUNCTION   : QueryCloseAllChildren()                    *
  850.  *                                        *
  851.  *  PURPOSE    : Asks the child windows if it is ok to close up app. Nothing*
  852.  *         is destroyed at this point. The z-order is not changed.    *
  853.  *                                        *
  854.  *  RETURNS    : TRUE - If all children agree to the query.            *
  855.  *         FALSE- If any one of them disagrees.                *
  856.  *                                        *
  857.  ****************************************************************************/
  858.  
  859. BOOL NEAR PASCAL QueryCloseAllChildren()
  860. {
  861.     register HWND hwndT;
  862.  
  863.     for ( hwndT = GetWindow (hwndMDIClient, GW_CHILD);
  864.       hwndT;
  865.       hwndT = GetWindow (hwndT, GW_HWNDNEXT)       ){
  866.  
  867.     /* Skip if an icon title window */
  868.     if (GetWindow (hwndT, GW_OWNER))
  869.         continue;
  870.  
  871.     if (SendMessage (hwndT, WM_QUERYENDSESSION, 0, 0L))
  872.         return FALSE;
  873.     }
  874.     return TRUE;
  875. }
  876.  
  877. /****************************************************************************
  878.  *                                        *
  879.  *  FUNCTION   : QueryCloseChild (hwnd)                     *
  880.  *                                        *
  881.  *  PURPOSE    : If the child MDI is unsaved, allow the user to save, not   *
  882.  *               save, or cancel the close operation.                       *
  883.  *                                        *
  884.  *  RETURNS    : TRUE  - if user chooses save or not save, or if the file   *
  885.  *                       has not changed.                                   *
  886.  *         FALSE - otherwise.                        *
  887.  *                                        *
  888.  ****************************************************************************/
  889.  
  890. BOOL NEAR PASCAL QueryCloseChild(hwnd)
  891. register HWND hwnd;
  892. {
  893.     char     sz [64];
  894.     register int i;
  895.  
  896.     /* Return OK if edit control has not changed. */
  897.     if (!GetWindowWord (hwnd, GWW_CHANGED))
  898.     return TRUE;
  899.  
  900.     GetWindowText (hwnd, sz, sizeof(sz));
  901.  
  902.     /* Ask user whether to save / not save / cancel */
  903.     i = MPError (hwnd,
  904.          MB_YESNOCANCEL|MB_ICONQUESTION,IDS_CLOSESAVE,
  905.          (LPSTR)sz);
  906.  
  907.     switch (i){
  908.     case IDYES:
  909.         /* User wants file saved */
  910.         SaveFile(hwnd);
  911.         break;
  912.  
  913.     case IDNO:
  914.         /* User doesn't want file saved */
  915.         break;
  916.  
  917.     default:
  918.         /* We couldn't do the messagebox, or not ok to close */
  919.         return FALSE;
  920.     }
  921.     return TRUE;
  922. }
  923. 
  924.